home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / cpp_libs / cool / cool.lha / ice / pisces / cpp / cpp4.c < prev    next >
C/C++ Source or Header  |  1991-09-04  |  17KB  |  606 lines

  1. /*
  2.  *                C P P 4 . C
  3.  *        M a c r o  D e f i n i t i o n s
  4.  *
  5.  * Edit History
  6.  * 31-Aug-84    MM    USENET net.sources release
  7.  * 04-Oct-84    MM    __LINE__ and __FILE__ must call ungetstring()
  8.  *            so they work correctly with token concatenation.
  9.  *            Added string formal recognition.
  10.  * 25-Oct-84    MM    "Short-circuit" evaluate #if's so that we
  11.  *            don't print unnecessary error messages for
  12.  *            #if !defined(FOO) && FOO != 0 && 10 / FOO ...
  13.  * 31-Oct-84    ado/MM    Added token concatenation
  14.  *  6-Nov-84    MM    Split off eval stuff
  15.  * 21-Oct-85    RMS    Rename `token' to `tokenbuf'.
  16.  *            In doundef, don't complain if arg already not defined.
  17.  * 20-Apr-90    MJF     Changed redefining of defined variable to a warning
  18.  * 18-May-90    MBN     Conditional compilation for COOL to get "clean" cpp
  19.  */
  20.  
  21. #include    <stdio.h>
  22. #include    <ctype.h>
  23. #include    "cppdef.h"
  24. #include    "cpp.h"
  25. /*
  26.  * parm[], parmp, and parlist[] are used to store #define() argument
  27.  * lists.  nargs contains the actual number of parameters stored.
  28.  */
  29. static char    parm[NPARMWORK + 1];    /* define param work buffer     */
  30. static char    *parmp;            /* Free space in parm        */
  31. static char    *parlist[LASTPARM];    /* -> start of each parameter    */
  32. static int    nargs;            /* Parameters for this macro    */
  33.  
  34. dodefine()
  35. /*
  36.  * Called from control when a #define is scanned.  This module
  37.  * parses formal parameters and the replacement string.  When
  38.  * the formal parameter name is encountered in the replacement
  39.  * string, it is replaced by a character in the range 128 to
  40.  * 128+NPARAM (this allows up to 32 parameters within the
  41.  * Dec Multinational range).  If cpp is ported to an EBCDIC
  42.  * machine, you will have to make other arrangements.
  43.  *
  44.  * There is some special case code to distinguish
  45.  *    #define foo    bar
  46.  * from    #define foo()    bar
  47.  *
  48.  * Also, we make sure that
  49.  *    #define    foo    foo
  50.  * expands to "foo" but doesn't put cpp into an infinite loop.
  51.  *
  52.  * A warning message is printed if you redefine a symbol to a
  53.  * different text.  I.e,
  54.  *    #define    foo    123
  55.  *    #define foo    123
  56.  * is ok, but
  57.  *    #define foo    123
  58.  *    #define    foo    +123
  59.  * is not.
  60.  *
  61.  * The following subroutines are called from define():
  62.  * checkparm    called when a token is scanned.  It checks through the
  63.  *        array of formal parameters.  If a match is found, the
  64.  *        token is replaced by a control byte which will be used
  65.  *        to locate the parameter when the macro is expanded.
  66.  * textput    puts a string in the macro work area (parm[]), updating
  67.  *        parmp to point to the first free byte in parm[].
  68.  *        textput() tests for work buffer overflow.
  69.  * charput    puts a single character in the macro work area (parm[])
  70.  *        in a manner analogous to textput().
  71.  */
  72. {
  73.     register int        c;
  74.     register DEFBUF        *dp;        /* -> new definition    */
  75.     int            isredefine;    /* TRUE if redefined    */
  76.     char            *old;        /* Remember redefined    */
  77.     extern int        save();        /* Save char in work[]    */
  78.  
  79.     if (type[(c = skipws())] != LET)
  80.         goto bad_define;
  81.     isredefine = FALSE;            /* Set if redefining    */
  82.     if ((dp = lookid(c)) == NULL)        /* If not known now    */
  83.         dp = defendel(tokenbuf, FALSE);    /* Save the name    */
  84.     else {                    /* It's known:        */
  85.         isredefine = TRUE;            /* Remember this fact    */
  86.         old = dp->repl;            /* Remember replacement    */
  87.         dp->repl = NULL;            /* No replacement now    */
  88.     }
  89.     parlist[0] = parmp = parm;        /* Setup parm buffer    */
  90.     if ((c = get()) == '(') {        /* With arguments?    */
  91.         nargs = 0;                /* Init formals counter    */
  92.         do {                /* Collect formal parms    */
  93.         if (nargs >= LASTPARM)
  94.             cfatal("Too many arguments for macro", NULLST);
  95.         else if ((c = skipws()) == ')')
  96.             break;            /* Got them all        */
  97.         else if (type[c] != LET)    /* Bad formal syntax    */
  98.             goto bad_define;
  99.         scanid(c);            /* Get the formal param    */
  100.         parlist[nargs++] = parmp;    /* Save its start    */
  101.         textput(tokenbuf);        /* Save text in parm[]    */
  102.         } while ((c = skipws()) == ',');    /* Get another argument    */
  103.         if (c != ')')            /* Must end at )    */
  104.         goto bad_define;
  105.         c = ' ';                /* Will skip to body    */
  106.     }
  107.     else {
  108.         /*
  109.          * DEF_NOARGS is needed to distinguish between
  110.          * "#define foo" and "#define foo()".
  111.          */
  112.         nargs = DEF_NOARGS;            /* No () parameters    */
  113.     }
  114.     if (type[c] == SPA)            /* At whitespace?    */
  115.         c = skipws();            /* Not any more.    */
  116.     workp = work;                /* Replacement put here    */
  117.     inmacro = TRUE;                /* Keep \<newline> now    */
  118.     while (c != EOF_CHAR && c != '\n') {    /* Compile macro body    */
  119. #if OK_CONCAT
  120.         if (c == '#') {            /* Token concatenation?    */
  121.           if((c = get()) != '#') {
  122.         save('#');            /* Lone #, just save it. */
  123.         if(type[c] == LET) {
  124.           if (checkparm(c, dp))     /* Single # next to parm */
  125.             workp[-2] = MAC_PARM + PAR_MAC;/* Mark next parameter */
  126.           c = get();}  
  127.             continue;}
  128.           while (workp > work && type[(unsigned char)workp[-1]] == SPA)
  129.         --workp;            /* Erase leading spaces    */
  130.           save(TOK_SEP);            /* Stuff a delimiter    */
  131.           c = skipws();            /* Eat whitespace    */
  132.           continue;
  133.         }
  134. #endif    /*  OK_CONCAT  */
  135.         switch (type[c]) {
  136.         case LET:
  137.         checkparm(c, dp);        /* Might be a formal    */
  138.         break;
  139.  
  140.         case DIG:                /* Number in mac. body    */
  141.         case DOT:                /* Maybe a float number    */
  142.         scannumber(c, save);        /* Scan it off        */
  143.         break;
  144.  
  145.         case QUO:                /* String in mac. body    */
  146. #if STRING_FORMAL
  147.         stparmscan(c, dp);        /* Do string magic    */
  148. #else
  149.         scanstring(c, save);
  150. #endif
  151.         break;
  152.  
  153.         case BSH:                /* Backslash        */
  154.         save('\\');
  155.         if ((c = get()) == '\n')
  156.             wrongline = TRUE;
  157.         save(c);
  158.         break;
  159.  
  160.         case SPA:                /* Absorb whitespace    */
  161.         /*
  162.          * Note: the "end of comment" marker is passed on
  163.          * to allow comments to separate tokens.
  164.          */
  165.         if (workp[-1] == ' ')        /* Absorb multiple    */
  166.             break;            /* spaces        */
  167.         else if (c == '\t')
  168.             c = ' ';            /* Normalize tabs    */
  169.         /* Fall through to store character            */
  170.         default:                /* Other character    */
  171.         save(c);
  172.         break;
  173.         }
  174.         c = get();
  175.     }
  176.     inmacro = FALSE;            /* Stop newline hack    */
  177.     unget();                /* For control check    */
  178.     if (workp > work && workp[-1] == ' ')    /* Drop trailing blank    */
  179.         workp--;
  180.     *workp = EOS;                /* Terminate work    */
  181.     dp->repl = savestring(work);        /* Save the string    */
  182.     dp->nargs = nargs;            /* Save arg count    */
  183. #if DEBUG
  184.     if (debug)
  185.         dumpadef("macro definition", dp);
  186. #endif
  187.     if (isredefine) {            /* Error if redefined    */
  188.         if ((old != NULL && dp->repl != NULL && !streq(old, dp->repl))
  189.          || (old == NULL && dp->repl != NULL)
  190.          || (old != NULL && dp->repl == NULL)) {
  191.         cwarn("Redefining defined variable \"%s\"", dp->name);
  192.         }
  193.         if (old != NULL)            /* We don't need the    */
  194.         free(old);            /* old definition now.    */
  195.     }     
  196.     return;
  197.  
  198. bad_define:
  199.     cerror("#define syntax error", NULLST);
  200.     inmacro = FALSE;            /* Stop <newline> hack    */
  201. }
  202.  
  203. int
  204. checkparm(c, dp)
  205. register int    c;
  206. DEFBUF        *dp;
  207. /*
  208.  * Replace this param if it's defined, returning TRUE.
  209.  * Note that the macro name is a possible replacement token.
  210.  * We stuff DEF_MAGIC in front of the token
  211.  * which is treated as a LETTER by the token scanner and eaten by
  212.  * the output routine.  This prevents the macro expander from
  213.  * looping if someone writes "#define foo foo".
  214.  */
  215. {
  216.     register int        i;
  217.     register char        *cp;
  218.  
  219.     scanid(c);                /* Get parm to tokenbuf */
  220.     for (i = 0; i < nargs; i++) {        /* For each argument    */
  221.         if (streq(parlist[i], tokenbuf)) {    /* If it's known    */
  222.         save(i + MAC_PARM);            /* Save a magic cookie    */
  223.         return(TRUE);            /* And exit the search    */
  224.         }
  225.     }
  226.     if (streq(dp->name, tokenbuf))        /* Macro name in body?    */
  227.         save(DEF_MAGIC);            /* Save magic marker    */
  228.     for (cp = tokenbuf; *cp != EOS;)    /* And save        */
  229.         save(*cp++);            /* The token itself    */
  230.     return(FALSE);
  231. }
  232.  
  233. #if STRING_FORMAL
  234. stparmscan(delim, dp)
  235. int        delim;
  236. register DEFBUF    *dp;
  237. /*
  238.  * Scan the string (starting with the given delimiter).
  239.  * The token is replaced if it is the only text in this string or
  240.  * character constant.  The algorithm follows checkparm() above.
  241.  * Note that scanstring() has approved of the string.
  242.  */
  243. {
  244.     register int        c;
  245.  
  246.     /*
  247.      * Warning -- this code hasn't been tested for a while.
  248.      * It exists only to preserve compatibility with earlier
  249.      * implementations of cpp.  It is not part of the Draft
  250.      * ANSI Standard C language.
  251.      */
  252.     save(delim);
  253.     instring = TRUE;
  254.     while ((c = get()) != delim
  255.          && c != '\n'
  256.          && c != EOF_CHAR) {
  257.         if (type[c] == LET)            /* Maybe formal parm    */
  258.         checkparm(c, dp);
  259.         else {
  260.         save(c);
  261.         if (c == '\\')
  262.             save(get());
  263.         }
  264.     }
  265.     instring = FALSE;
  266.     if (c != delim)
  267.         cerror("Unterminated string in macro body", NULLST);
  268.     save(c);
  269. }
  270. #endif
  271.  
  272. doundef()
  273. /*
  274.  * Remove the symbol from the defined list.
  275.  * Called from the #control processor.
  276.  */
  277. {
  278.   register int c;
  279.  
  280.   if (type[(c = skipws())] != LET)
  281.     cerror("Illegal #undef argument", NULLST);
  282.   else
  283.     {
  284.       scanid(c);                /* Get name to tokenbuf */
  285.       defendel(tokenbuf, TRUE);
  286.     }
  287. }
  288.  
  289. textput(text)
  290. char        *text;
  291. /*
  292.  * Put the string in the parm[] buffer.
  293.  */
  294. {
  295.     register int    size;
  296.  
  297.     size = strlen(text) + 1;
  298.     if ((parmp + size) >= &parm[NPARMWORK])
  299.         cfatal("Macro work area overflow", NULLST);
  300.     else {
  301.         strcpy(parmp, text);
  302.         parmp += size;
  303.     }
  304. }
  305.  
  306. charput(c)
  307. register int    c;
  308. /*
  309.  * Put the byte in the parm[] buffer.
  310.  */
  311. {
  312.     if (parmp >= &parm[NPARMWORK])
  313.         cfatal("Macro work area overflow", NULLST);
  314.     else {
  315.         *parmp++ = c;
  316.     }
  317. }
  318.  
  319. /*
  320.  *        M a c r o   E x p a n s i o n
  321.  */
  322.  
  323. expand(tokenp)
  324. register DEFBUF    *tokenp;
  325. /*
  326.  * Expand a macro.  Called from the cpp mainline routine (via subroutine
  327.  * macroid()) when a token is found in the symbol table.  It calls
  328.  * expcollect() to parse actual parameters, checking for the correct number.
  329.  * It then creates a "file" containing a single line containing the
  330.  * macro with actual parameters inserted appropriately.  This is
  331.  * "pushed back" onto the input stream.  (When the get() routine runs
  332.  * off the end of the macro line, it will dismiss the macro itself.)
  333.  */
  334. {
  335.     register int        c;
  336.  
  337. #if DEBUG
  338.     if (debug)
  339.         dumpadef("expand entry", tokenp);
  340. #endif    
  341.     /*
  342.      * If no macro is pending, save the name of this macro
  343.      * for an eventual error message.
  344.      */
  345.     if (recursion++ == 0)
  346.         macro = tokenp;
  347.     else if (recursion == RECURSION_LIMIT) {
  348.         cerror("Recursive macro definition of \"%s\"", tokenp->name);
  349.         fprintf(stderr, "(Defined by \"%s\")\n", macro->name);
  350.         if (rec_recover) {
  351.         do {
  352.             c = get();
  353.         } while (infile != NULL && infile->fp == NULL);
  354.         unget();
  355.         recursion = 0;
  356.         return;
  357.         }
  358.     }
  359.     /*
  360.      * Here's a macro to expand.
  361.      */
  362.     nargs = 0;                /* Formals counter    */
  363.     parmp = parm;                /* Setup parm buffer    */
  364.     switch (tokenp->nargs) {
  365.     case DEF_BUILTIN:
  366.       (tokenp->expander)(tokenp->repl);    /* Builtin  macros      */
  367.       break;
  368.     default:
  369.         /*
  370.          * Nothing funny about this macro.
  371.          */
  372.         if (tokenp->nargs < 0)
  373.         cfatal("Bug: Illegal __ macro \"%s\"", tokenp->name);
  374.         while ((c = skipws()) == '\n')    /* Look for (, skipping    */
  375.         wrongline = TRUE;        /* spaces and newlines    */
  376.         if (c != '(') {
  377.         /*
  378.          * If the programmer writes
  379.          *    #define foo() ...
  380.          *    ...
  381.          *    foo [no ()]
  382.          * just write foo to the output stream.
  383.          */
  384.         unget();
  385.         cwarn("Macro \"%s\" needs arguments", tokenp->name);
  386.         fputs(tokenp->name, stdout);
  387.         return;
  388.         }
  389.         else if (expcollect()) {        /* Collect arguments    */
  390.         if (tokenp->nargs != nargs) {    /* Should be an error?    */
  391.             cwarn("Wrong number of macro arguments for \"%s\"",
  392.             tokenp->name);
  393.         }
  394. #if DEBUG
  395.         if (debug)
  396.             dumpparm("expand");
  397. #endif
  398.         }                /* Collect arguments        */
  399.     case DEF_NOARGS:        /* No parameters just stuffs    */
  400.         expstuff(tokenp);        /* Do actual parameters        */
  401.     }                /* nargs switch            */
  402. }
  403.  
  404. void
  405. expand_line (dp)
  406.   char* dp;
  407. {
  408.   sprintf(work, "%d", line);
  409.   ungetstring(work);
  410. }
  411.  
  412. void
  413. expand_file (dp)
  414.      char *dp;
  415. {
  416.   register FILEINFO    *file;
  417.               /* Find bottom level file (the file being compiled) */
  418.   for (file = infile; file != NULL; file = file->parent) {
  419.     if (file->parent == NULL) {
  420.       sprintf(work, "\"%s\"", (file->progname != NULL)
  421.           ? file->progname : file->filename);
  422.       ungetstring(work);
  423.       break;
  424.     }
  425.   }
  426. }
  427.  
  428. #ifndef COOL
  429. /* We need this routine here only when we are building a clean, ie. non-COOL
  430.  * preprocessor. For COOL, this function is defined in cpp7.c
  431.  */
  432. FILEINFO*
  433. get_temp_file (bufsize, name)
  434.      int bufsize;
  435.      char* name;
  436. {
  437.   extern FILEINFO    *getfile();
  438.   FILEINFO* file = getfile(bufsize, name);
  439.   infile = file->parent;
  440.   file->parent = NULL;
  441.   line = infile->line;
  442.   return(file);
  443. }
  444. #endif
  445.  
  446. FILE_LOCAL int
  447. expcollect()
  448. /*
  449.  * Collect the actual parameters for this macro.  TRUE if ok.
  450.  */
  451. {
  452.     register int    c;
  453.     register int    paren;            /* For embedded ()'s    */
  454.     extern int    charput();
  455.  
  456.     for (;;) {
  457.         paren = 0;                /* Collect next arg.    */
  458.         while ((c = skipws()) == '\n')    /* Skip over whitespace    */
  459.         wrongline = TRUE;        /* and newlines.    */
  460.         if (c == ')') {            /* At end of all args?    */
  461.         /*
  462.          * Note that there is a guard byte in parm[]
  463.          * so we don't have to check for overflow here.
  464.          */
  465.         *parmp = EOS;            /* Make sure terminated    */
  466.         break;                /* Exit collection loop    */
  467.         }
  468.         else if (nargs >= LASTPARM)
  469.         cfatal("Too many arguments in macro expansion", NULLST);
  470.         parlist[nargs++] = parmp;        /* At start of new arg    */
  471.         for (;; c = cget()) {        /* Collect arg's bytes    */
  472.         if (c == EOF_CHAR) {
  473.             cfatal("end of file within macro argument", NULLST);
  474.             return (FALSE);        /* Sorry.        */
  475.         }
  476.         else if (c == '\\') {        /* Quote next character    */
  477.             charput(c);            /* Save the \ for later    */
  478.             charput(cget());        /* Save the next char.    */
  479.             continue;            /* And go get another    */
  480.         }
  481.         else if (type[c] == QUO) {    /* Start of string?    */
  482.             scanstring(c, charput);    /* Scan it off        */
  483.             continue;            /* Go get next char    */
  484.         }
  485.         else if (c == '(')        /* Worry about balance    */
  486.             paren++;            /* To know about commas    */
  487.         else if (c == ')') {        /* Other side too    */
  488.             if (paren == 0) {        /* At the end?        */
  489.             unget();        /* Look at it later    */
  490.             break;            /* Exit arg getter.    */
  491.             }
  492.             paren--;            /* More to come.    */
  493.         }
  494.         else if (c == ',' && paren == 0) /* Comma delimits args    */
  495.             break;
  496.         else if (c == '\n')        /* Newline inside arg?    */
  497.             wrongline = TRUE;        /* We'll need a #line    */
  498.         charput(c);            /* Store this one    */
  499.         }                    /* Collect an argument    */
  500.         charput(EOS);            /* Terminate argument    */
  501. #if DEBUG
  502.         if (debug)
  503.             printf("parm[%d] = \"%s\"\n", nargs, parlist[nargs - 1]);
  504. #endif
  505.     }                    /* Collect all args.    */
  506.     return (TRUE);                /* Normal return    */
  507. }
  508.  
  509. FILE_LOCAL
  510. expstuff(tokenp)
  511. DEFBUF        *tokenp;        /* Current macro being expanded    */
  512. /*
  513.  * Stuff the macro body, replacing formal parameters by actual parameters.
  514.  */
  515. {
  516.     register int    c;            /* Current character    */
  517.     register char    *inp;            /* -> repl string    */
  518.     register char    *defp;            /* -> macro output buff    */
  519.     int        size;            /* Actual parm. size    */
  520.     char        *defend;        /* -> output buff end    */
  521.     int        string_magic;        /* String formal hack    */
  522.     FILEINFO    *file;                /* Funny #include    */
  523.     extern FILEINFO    *getfile();
  524.     extern FILEINFO    *get_temp_file();
  525.  
  526.     file = getfile(NBUFF, tokenp->name);
  527.     inp = tokenp->repl;            /* -> macro replacement    */
  528.     defp = file->buffer;            /* -> output buffer    */
  529.     defend = defp + (NBUFF - 24);        /* Note its end        */
  530.     if (inp != NULL) {
  531.         while ((c = (*inp++ & 0xFF)) != EOS) {
  532.           if (defp >= defend) {        /* If out of space      */
  533.         FILEINFO* new = get_temp_file(NBUFF, file->filename);
  534.         new->parent = file->parent; /* When new ends read from infile */
  535.         file->parent = new;        /* When file ends read from new   */
  536.         file = new;
  537.         *defp = EOS;
  538.         defp = file->buffer;
  539.         defend = defp + (NBUFF - 24);
  540.           }
  541.  
  542.           if (c >= MAC_PARM && c <= (MAC_PARM + PAR_MAC)) {
  543.         string_magic = (c == (MAC_PARM + PAR_MAC));
  544.         if (string_magic) {        /* When quoted parameter */
  545.           c = (*inp++ & 0xFF);
  546.           *defp++ = '\"';
  547.         }
  548.         /*
  549.          * Replace formal parameter by actual parameter string.
  550.          */
  551.         if ((c -= MAC_PARM) < nargs) {
  552.           size = strlen(parlist[c]);
  553.           if ((defp + size + 24) >= defend) {
  554.             *defp = EOS;        /* If out of space */
  555.             defend = defp;
  556.             if (string_magic) inp--; 
  557.             inp--;            /* backup and try again */
  558.             continue;
  559.           }
  560.           if (string_magic) {        /* When quoted parameter */
  561.             char* p = parlist[c];
  562.             for(; (c = *p++) != EOS;) {
  563.               switch (c) {
  564.               case '\"':
  565.               case '\\':
  566.             *defp++ = '\\';
  567.               default:
  568.             *defp++ = c;
  569.               } /* switch */
  570.             } /* for */
  571.             *defp++ = '\"';
  572.           } else {
  573.             strncpy(defp, parlist[c], size);
  574.             defp += size;
  575.           } /* if string_magic */
  576.         } /* if valid parm */
  577.           } /* if parm */
  578.           else
  579.         *defp++ = c;
  580.         }
  581.       }
  582.     *defp = EOS;
  583. #if DEBUG
  584.     if (debug > 1)
  585.         printf("macroline: \"%s\"\n", file->buffer);
  586. #endif
  587. }
  588.  
  589. #if DEBUG
  590. dumpparm(why)
  591. char        *why;
  592. /*
  593.  * Dump parameter list.
  594.  */
  595. {
  596.     register int    i;
  597.  
  598.     printf("dump of %d parameters (%d bytes total) %s\n",
  599.         nargs, parmp - parm, why);
  600.     for (i = 0; i < nargs; i++) {
  601.         printf("parm[%d] (%d) = \"%s\"\n",
  602.         i + 1, strlen(parlist[i]), parlist[i]);
  603.     }
  604. }
  605. #endif
  606.